package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.base.ResponseResult;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.DeviceLocationTypeEnum;
import com.zzyl.enums.DevicePhysicalLocationTypeEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceDataMapper;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.utils.StringUtils;
import com.zzyl.vo.DeviceDataGraphVo;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class DeviceServiceImpl implements DeviceService {

    @Autowired
    private Client client;

    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private DeviceDataMapper deviceDataMapper;

    /**
     * 同步数据
     */
    @Override
    public void syncProductList() {
        //请求参数
        QueryProductListRequest request = new QueryProductListRequest();
        request.setPageSize(200);
        request.setCurrentPage(1);
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        //调用第三方查询产品列表
        QueryProductListResponse response;
        try {
            response = client.queryProductList(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        //判断，如果数据为空，则中断请求
        if (!response.getBody().success) {
            throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
        }

        //获取数据，存储到redis
        List<ProductVo> productVoList = response.getBody().getData().getList().getProductInfo().stream().map(
                p -> BeanUtil.toBean(p, ProductVo.class)
        ).collect(Collectors.toList());
        //存储到redis
        redisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCT_KEY, JSONUtil.toJsonStr(productVoList),24, TimeUnit.HOURS);
    }

    //查询所有产品列表
    @Override
    public Object allProduct() {
        //从缓存中获取数据
        String jsonStr = redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_KEY);
        //如果为空就返回空集合
        if (StringUtils.isEmpty(jsonStr)) {
            return Collections.emptyList();
        }
        //转换数据，并返回
        return JSONUtil.toList(jsonStr, ProductVo.class);
    }

    //添加设备
    @Override
    public Object registerDevice(DeviceDto deviceDto) {
        //检验设备名称是否重复
        Long count = deviceMapper.countByDeviceName(deviceDto.getDeviceName());
        if (count > 0) {
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }
        //iot新增设备
        RegisterDeviceRequest registerDeviceRequest = deviceDto.getRegisterDeviceRequest();
        registerDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        RegisterDeviceResponse response = null;
        try {
            response =client.registerDevice(registerDeviceRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        //接口是否调通
        if (response == null || !response.getBody().success) {
            throw new RuntimeException(response.getBody().getErrorMessage());
        }
        //属性拷贝
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        device.setIotId(response.getBody().getData().getIotId());
        //产品名称
        QueryProductRequest queryProductRequest = new QueryProductRequest();
        queryProductRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryProductRequest.setProductKey(deviceDto.getProductKey());
        QueryProductResponse queryProductResponse;
        try {
            queryProductResponse = client.queryProduct(queryProductRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        //设置产品名称
        if (queryProductResponse.getBody().success) {
            device.setProductName(queryProductResponse.getBody().getData().productName);
        }
        //如果设备绑定的位置是随身设备，则把物理绑定位置为-1
        //原因是为了后期方便通过位置字段查询老人数据
        if (device.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())) {
            device.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }
        //设置门禁
        device.setHaveEntranceGuard(0);
        //保存设备
        try {
            deviceMapper.insertSelective(device);
        } catch (Exception e) {

            //删除iot中的设备数据
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setDeviceName(device.getDeviceName());
            deleteDeviceRequest.setIotId(device.getIotId());
            deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            deleteDeviceRequest.setProductKey(device.getProductKey());

            try {
                client.deleteDevice(deleteDeviceRequest);
            } catch (Exception ex) {
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
           throw new BaseException(BasicEnum.RE_SELECT_PRODUCT);

        }

        return ResponseResult.success();
        //1.判断新增的设备名称是否重复
        //1.1 根据设备名称查询指定设备数量

        //1.2 判断设备数据是否大于0，大于0说明存在，抛出异常注册设备失败

        //2.调用阿里云IOT远程接口注册设备（接口名字：RegisterDevice）
        //2.1 完善请求对象IotInstanceId属性，请求对象 RegisterDeviceRequest(前端已经传递封装了 ProductKey，DeviceName，Nickname)
        //2.2 执行接口
        //2.3 判断远程接口调用是否成功（Success属性）
        //2.4 定义变量接收物联网设备的id

        //3.调用阿里云IOT远程接口查询产品详情（QueryProduct）
        //3.1 封装请求对象 手动封装QueryProductRequest(ProductKey,IotInstanceId)
        //3.2 执行接口
        //3.3 判断远程接口调用是否成功（Success属性）
        //3.4 定义变量接收 产品名字

        //4.判断位置类型是否是绑定随身设备
        //4.1 是，设置物理位置类型为-1

        //5.将设备数据插入数据库
        //5.1 完善数据，设置没有门禁，为0
        //5.2 完善数据，封装产品名字
        //5.3 完善数据，封装设备id
        //5.4 插入数据库
        //5.5 插入失败（发生异常），调用阿里云IOT远程接口删除设备（DeleteDevice）
        //5.5.1 封装请求对象DeleteDeviceRequest(IotInstanceId,IotId)
    }
    //分页查询
    @Override
    public PageResponse<DeviceVo> pageQueryDevice(DevicePageQueryDto devicePageQueryDto) {
        //开启分页
        PageHelper.startPage(devicePageQueryDto.getPageNum(),devicePageQueryDto.getPageSize());
        //进行封装
        Page<DeviceVo> page =deviceMapper.selectByPage(devicePageQueryDto);
          //类型转化为需要的类型
        return PageResponse.of(page,DeviceVo.class);
    }
//条件查询
    @Override
    public ResponseResult<DeviceVo> queryDeviceDetail(QueryDeviceDetailRequest request) {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDeviceDetailResponse response;
        try {
            response=client.queryDeviceDetail(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        //判断接口是否调通
        if (!response.getBody().getSuccess()){
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        //查询数据库
        DeviceVo deviceVo=deviceMapper.selectByIotId(response.getBody().getData().getIotId());
        QueryDeviceDetailResponseBody.QueryDeviceDetailResponseBodyData data = response.getBody().getData();
        BeanUtil.copyProperties(data,deviceVo, CopyOptions.create().ignoreNullValue());
        return ResponseResult.success(deviceVo);
        //1.调用iot查询设备详情接口获取详情数据
        //1.1 封装请求对象（IotInstanceId，其他属性request根据前端的参数封装好了）
        //1.2 执行接口
        //1.3 获取详情数据
        //2.调用mapper根据设备id查询数据库设备数据DeviceVo
        //3.将IOT获取设备详情数据和数据库获取的DeviceVo数据合并
        //4.返回数据
    }
//查询已发布的物模型数据
    @Override
    public ResponseResult QueryThingModelPublished(QueryThingModelPublishedRequest request) {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryThingModelPublishedResponse response;
        try {
            response = client.queryThingModelPublished(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
        }
        return ResponseResult.success(response.getBody().getData());
    }

    @Override
    public ResponseResult QueryDevicePropertyStatus(QueryDevicePropertyStatusRequest request) {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDevicePropertyStatusResponse response;
        try {
            response=client.queryDevicePropertyStatus(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
        }
        return ResponseResult.success(response.getBody().getData());
    }
//按天查询
    @Override
    public Object queryDeviceDataListByDay(String iotId, String functionId, Long startTime, Long endTime) {
        //按天聚合数据
        List<DeviceDataGraphVo> deviceDataGraphVoList=deviceDataMapper.queryDeviceDataListByDay(iotId,functionId, LocalDateTimeUtil.of(startTime),LocalDateTimeUtil.of(endTime));
        //构建一个24小时的集合
        List<DeviceDataGraphVo> list=DeviceDataGraphVo.dayInstance(LocalDateTimeUtil.of(startTime));
        //转化为map集合
        Map<String,Double> map=deviceDataGraphVoList.stream().collect(Collectors.toMap(DeviceDataGraphVo::getDateTime,DeviceDataGraphVo::getDataValue));
         list.forEach(deviceDataGraphVo -> {
             //从map中获取值，如果为空则给默认值
             Double aDouble = map.get(deviceDataGraphVo.getDateTime()) == null ? 0.0 : map.get(deviceDataGraphVo.getDateTime());
             deviceDataGraphVo.setDataValue(aDouble);
         });
        return list;
    }
//按周查询
    @Override
    public Object queryDeviceDataListByWeek(String iotId, String functionId, Long startTime, Long endTime) {
        //按日聚合数据
        List<DeviceDataGraphVo> deviceDataGraphVoList = deviceDataMapper.queryDeviceDataListByDay(iotId, functionId, LocalDateTimeUtil.of(startTime), LocalDateTimeUtil.of(endTime));
        //构建一个24小时的集合
        List<DeviceDataGraphVo> list = DeviceDataGraphVo.dayInstance(LocalDateTimeUtil.of(startTime));
        //转换为map
        Map<String, Double> map = deviceDataGraphVoList.stream().collect(Collectors.toMap(DeviceDataGraphVo::getDateTime, DeviceDataGraphVo::getDataValue));
        list.forEach(d -> {
            //从map获取值，如果为空，则给默认为0
            Double val = map.get(d.getDateTime()) == null ? 0.0 : map.get(d.getDateTime());
            d.setDataValue(val);
        });
        return list;
    }
}